#!/usr/bin/env python
# encoding: utf-8
"""
SigmodRepeat.py

Created by philippe on 2010-07-27.
Copyright (c) 2010 . All rights reserved.
"""

import core.modules.module_registry 
#import core.modules.basic_modules
from core.configuration import ConfigurationObject
from core.modules.vistrails_module import Module, ModuleError
import os
import sys
import subprocess
import shlex
import xmlrpclib

version = "0.1.0" 
name = "Sigmod Repeatability" 
identifier = "dk.itu.cr.sigmodrepeatability"


configuration = ConfigurationObject(path=(None, str), debug=False)

class LocalDataExec(Module): 
    """LocalDataExec is a module that wraps up a local command line 
    executable returning data"""
    def compute(self): 
        workingdir = self.getInputFromPort("workingdir")
        cmdstring = self.getInputFromPort("cmd") 
        argstring = self.getInputFromPort("argstring") 
        if argstring == '':
            args = []
        else:
            args = shlex.split(argstring)
        exe = [cmdstring] + args
        stdoutdata = self.execute(workingdir, exe) 
        if configuration.debug:
            print "stdoutdata: " + stdoutdata
        self.setResult("stdoutdata", stdoutdata)
        
    def execute(self, workingdir, exe):
        if configuration.debug:
            print exe
        try:
            p = subprocess.Popen(exe, bufsize=4096, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=workingdir)
            # Should move to files instead of buffered pipes for stoutdata/stderrdata in 0.1.1
            # Should analyze stderr and raise exception if needed
            (stdoutdata,stderr) = p.communicate()
            if stdoutdata != None:
                return stdoutdata
            else:
                return "Error: "+ stderr
        except OSError, e:
            print >>sys.stderr, "Execution failed: ", e

class LocalControlExec(Module): 
    """LocalControlExec is a module that wraps up a local command line 
    pass/fail executable"""
    def compute(self): 
        workingdir = self.getInputFromPort("workingdir")
        cmdstring = self.getInputFromPort("cmd") 
        argstring = self.getInputFromPort("argstring") 
        if argstring == '':
            args = []
        else:
            args = shlex.split(argstring)
        exe = [cmdstring] + args
        retcode = self.execute(workingdir, exe) 
        if configuration.debug:
            print "retcode: " + retcode
        self.setResult("retcode", retcode)

    def execute(self, workingdir, exe):
        if configuration.debug:
            print exe
        try:
            p = subprocess.Popen(exe, cwd=workingdir, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            retcode = p.wait(exe)
            return retcode
        except OSError, e:
            print >>sys.stderr, "Execution failed: ", e



class RemoteControlExec(Module):
    """RemoteExecWrapper is a module that wraps up a remote pass/fail 
    command line executable via XML RPC"""
    def compute(self): 
        cmd = self.getInputFromPort("cmd") 
        server = self.getInputFromPort("server")
        port = self.getInputFromPort("port")
        argstring = self.getInputFromPort("argstring") 
        args = shlex.split(argstring)   
        print args         
        rc = self.execute(server,port,cmd, args) 
        if configuration.debug:
            print "retcode: " + str(rc)
        self.setResult("retcode", str(rc))

    def execute(self,server,port,cmd,args):
        try:
            # connect to server at port
            httpstring = "http://"+server+":"+port+"/"
            p =  xmlrpclib.ServerProxy(httpstring)
            if len(args) == 1:
                if (args[0]==''): 
                    args_pp = '()'
                else:
                    args_pp = '(\''+ str(args[0])+'\')'
            else:
                args_pp = str(tuple(args))
            evalstring = "p."+ cmd + args_pp
            print evalstring
            return eval(evalstring) 
        except xmlrpclib.Fault, fault:
             if configuration.debug:
                 print fault.faultString
             return 10
        except xmlrpclib.ProtocolError, err:
             if configuration.debug:
                 print err.errmsg
             return 10                        
        except OSError, e:
             print >>sys.stderr, "Execution failed: ", e
    
    
class RemoteDataExec(Module):
     """RemoteExecWrapper is a module that wraps up a remote command
     line executable that returns data via XML RPC"""
     def compute(self): 
         print 'RemoteDataExec'
         cmd = self.getInputFromPort("cmd") 
         server = self.getInputFromPort("server")
         port = self.getInputFromPort("port")
         argstring = self.getInputFromPort("argstring") 
         args = shlex.split(argstring)
         stdoutdata = self.execute(server,port,cmd, args) 
         if configuration.debug:
             print "stdoutdata: " + stdoutdata
         self.setResult("stdoutdata", stdoutdata)

     def execute(self,server,port,cmd,args):
         try:
             # connect to server at port
             httpstring = "http://"+server+":"+port+"/"
             print httpstring
             p =  xmlrpclib.ServerProxy(httpstring)
             if len(args) == 1:
                 if (args[0]==''): 
                     args_pp = '()'
                 else:
                     args_pp = '('+ str(args[0])+')'
             else:
                 args_pp = str(tuple(args))
             evalstring = "p."+ cmd + args_pp
             print evalstring
             stdout = eval(evalstring) 
             return stdout
         except xmlrpclib.Fault, fault:
              if configuration.debug:
                  print fault.faultString
              return "Server Error: " + fault.faultString 
         except xmlrpclib.ProtocolError, err:
              if configuration.debug:
                  print err.errmsg
              return "Server Error: " + err.errmsg                        
         except OSError, e:
              print >>sys.stderr, "Execution failed: ", e


###############################################################################

def initialize(*args, **keywords):
    reg = core.modules.module_registry.registry
    
    reg.add_module(LocalDataExec) 
    reg.add_input_port(LocalDataExec, "workingdir",
                        (core.modules.basic_modules.String, "the working directory for the command"))
    reg.add_input_port(LocalDataExec, "cmd", 
                       (core.modules.basic_modules.String, "The executable name")) 
    reg.add_input_port(LocalDataExec, "argstring",
                        (core.modules.basic_modules.String, "the argument string")) 
    reg.add_output_port(LocalDataExec, "stdoutdata",
                        (core.modules.basic_modules.String, "the standard output data")) 
 
    reg.add_module(LocalControlExec) 
    reg.add_input_port(LocalControlExec, "workingdir",
                        (core.modules.basic_modules.String, "the working directory for the command"))
    reg.add_input_port(LocalControlExec, "cmd", 
                       (core.modules.basic_modules.String, "The executable name")) 
    reg.add_input_port(LocalControlExec, "argstring",
                        (core.modules.basic_modules.String, "the argument string")) 
    reg.add_output_port(LocalControlExec, "retcode",
                        (core.modules.basic_modules.String, "Return code: 0 if OK, non 0 else")) 

    reg.add_module(RemoteDataExec) 
    reg.add_input_port(RemoteDataExec, "cmd", 
                       (core.modules.basic_modules.String, "The executable name")) 
    reg.add_input_port(RemoteDataExec, "server",
                       (core.modules.basic_modules.String, "the remote server"))
    reg.add_input_port(RemoteDataExec, "port",
                       (core.modules.basic_modules.String, "service port on the remote server"))
    reg.add_input_port(RemoteDataExec, "argstring",
                        (core.modules.basic_modules.String, "the argument string")) 
    reg.add_output_port(RemoteDataExec, "stdoutdata",
                        (core.modules.basic_modules.String, "the output data from the remote executable")) 
 
    reg.add_module(RemoteControlExec) 
    reg.add_input_port(RemoteControlExec, "cmd", 
                       (core.modules.basic_modules.String, "The executable name"))
    reg.add_input_port(RemoteControlExec, "server",
                      (core.modules.basic_modules.String, "the remote server"))
    reg.add_input_port(RemoteControlExec, "port",
                      (core.modules.basic_modules.String, "service port on the remote server"))
    reg.add_input_port(RemoteControlExec, "argstring",
                        (core.modules.basic_modules.String, "the argument string")) 
    reg.add_output_port(RemoteControlExec, "retcode",
                        (core.modules.basic_modules.String, "0 if failed -  0 if OK, non 0 else")) 
